/**
 * Copyright (c) 2009-2014 XTEAM
 * All rights reserved.
 */
/**
 * File：GradeRuleUtil.java
 * History:
 *         2014-1-7: Initially created, Chrise.
 */
package com.xteam.ecsystem.utils;

import java.util.Stack;
import java.util.regex.Pattern;

/**
 * 等级规则工具类。
 * @author Chrise
 */
public class GradeRuleUtil {
	private static final char LEFT_PARENTHESES = '(';
	private static final char RIGHT_PARENTHESES = ')';
	private static final char EXPRESSION_VALUE = 'V';
	private static final char LOGIC_AND = '&';
	private static final char LOGIC_OR = '|';
	
	private static final String LITTLE_EQUAL_SYMBOL_REGEX = "<=";
	private static final String BIG_EQUAL_SYMBOL_REGEX = ">=";
	private static final String NOT_EQUAL_SYMBOL_REGEX = "!=";
	private static final String AND_SYMBOL_REGEX = "&&";
	private static final String OR_SYMBOL_REGEX = "\\|\\|";
	
	private static final String LITTLE_EQUAL_SYMBOL_REPLACE = "@";
	private static final String BIG_EQUAL_SYMBOL_REPLACE = "#";
	private static final String NOT_EQUAL_SYMBOL_REPLACE = "!";
	private static final String AND_SYMBOL_REPLACE = "&";
	private static final String OR_SYMBOL_REPLACE = "|";
	
	private static final String BLANK_REGEX = "\\s";
	private static final String SYMBOL_REGEX = "[\\(\\)\\+\\-\\*/%<@>#=!&\\|]";
	
	private static final String DEGRADE_VALUE_REGEX = "(@buys_new)|0|[1-9]\\d*";
	private static final String UPGRADE_VALUE_REGEX = "(@buys_total)|0|[1-9]\\d*";
	
	private static final Pattern PATTERN_ARITHMETIC = Pattern.compile("[\\+\\-\\*/%]");
	private static final Pattern PATTERN_RELATION = Pattern.compile("[<@>#=!]");
	private static final Pattern PATTERN_LOGIC = Pattern.compile("[&\\|]");
	
	/**
	 * 验证。
	 * @author Chrise 2014-1-7
	 * @param input
	 * @param upgrade
	 * @return
	 */
	public static boolean validate(String input, boolean upgrade) {
		if (input == null) return false;
		
		String vr = DEGRADE_VALUE_REGEX;
		if (upgrade) vr = UPGRADE_VALUE_REGEX;
		
		//表达式预处理(即去除表达式中的空格并将参数、数字和组合符号为单一字符)
		String ev = String.valueOf(EXPRESSION_VALUE);
		String expression = input.replaceAll(BLANK_REGEX, "")
		   						 .replaceAll(vr, ev)
		   						 .replaceAll(LITTLE_EQUAL_SYMBOL_REGEX, LITTLE_EQUAL_SYMBOL_REPLACE)
		   						 .replaceAll(BIG_EQUAL_SYMBOL_REGEX, BIG_EQUAL_SYMBOL_REPLACE)
		   						 .replaceAll(NOT_EQUAL_SYMBOL_REGEX, NOT_EQUAL_SYMBOL_REPLACE)
		   						 .replaceAll(AND_SYMBOL_REGEX, AND_SYMBOL_REPLACE)
		   						 .replaceAll(OR_SYMBOL_REGEX, OR_SYMBOL_REPLACE);
		
		//检查表达式中的参数和数字的合法性
		String[] values = expression.split(SYMBOL_REGEX);
		for (String value : values) {
			if (!"".equals(value) && !ev.equals(value)) return false;
		}
		
		if (PATTERN_ARITHMETIC.matcher(expression).find()) {
			//分析算术运算符
			expression = analysis(expression, PATTERN_ARITHMETIC, false);
			if (expression == null) return false;
		}
		
		if (PATTERN_RELATION.matcher(expression).find()) {
			//分析关系运算符
			expression = analysis(expression, PATTERN_RELATION, true);
			if (expression == null) return false;
		}
		
		if (PATTERN_LOGIC.matcher(expression).find()) {
			//分析逻辑运算符
			expression = analysis(expression, PATTERN_LOGIC, false);
			if (expression == null) return false;
		}
		
		//表达式分析结果为一个单值则表达式合法
		if (ev.equals(expression)) return true;
		
		return false;
	}
	
	/**
	 * 分析。
	 * @author Chrise 2014-1-7
	 * @param expression
	 * @param pattern
	 * @param relation
	 * @return
	 */
	private static String analysis(String expression, Pattern pattern, boolean relation) {
		Stack<Character> stack = new Stack<Character>();
		
		int index = 0, length = expression.length();
		while (index < length) {
			char c = expression.charAt(index);
			
			if (stack.empty()) {
				//栈空时直接入栈并移动至下一个字符
				stack.push(c);
				index ++;
				continue;
			}
			
			//如果当前字符是运算符则合并当前运算符关联的表达式为单值
			if (pattern.matcher(String.valueOf(c)).matches()) {
				char l = stack.peek();
				if (!relation && l == RIGHT_PARENTHESES) {
					//前一个字符是右括号时直接入栈并移动至下一个字符(除关系运算符外的运算符的左边可以是括号包围的同级运算表达式)
					stack.push(c);
					index ++;
					continue;
				}
				if (l != EXPRESSION_VALUE) return null;		//运算符的左边不是表达式值则不合法
				
				if (index + 1 >= length) return null;		//表达式不完整
				
				char n = expression.charAt(index + 1);
				if (!relation && n == LEFT_PARENTHESES) {
					//下一个字符是左括号时直接入栈并移动至下一个字符(除关系运算符外的运算符的右边可以是括号包围的同级运算表达式)
					stack.push(c);
					index ++;
					continue;
				}
				if (n != EXPRESSION_VALUE) return null;		//运算符的右边不是表达式值则不合法
				
				if (relation && index + 2 < length) {
					//关系表达式的右边只能是右括号或逻辑运算符
					n = expression.charAt(index + 2);
					if (n != RIGHT_PARENTHESES && n != LOGIC_AND && n != LOGIC_OR) return null;
				}
				
				//移动至运算符的再下一个字符
				index += 2;
				continue;
			}
			
			//如果当前字符是右括号则合并括号包围的表达式为单值
			if (c == RIGHT_PARENTHESES) {
				if (stack.size() < 2) return null;	//表达式不完整
				
				char t = stack.pop();
				char l = stack.peek();
				
				//如果栈顶字符为表达式值且前一个字符为左括号
				if (t == EXPRESSION_VALUE && l == LEFT_PARENTHESES) {
					//合并括号包围的表达式为单值(左括号出栈且表达式值入栈)
					stack.pop();
					stack.push(t);
					
					//移动至下一个字符
					index ++;
					continue;
				}
				
				stack.push(t);		//还原(出栈的表达式值入栈)
				stack.push(c);		//当前字符入栈
				
				//移动至下一个字符
				index ++;
				continue;
			}
			
			//当前字符入栈并移动至下一个字符
			stack.push(c);
			index ++;
		}
		
		//将栈中字符还原为表达式
		StringBuilder sb = new StringBuilder();
		while (!stack.empty()) {
			sb.insert(0, stack.pop());
		}
		expression = sb.toString();
		
		if (!relation && pattern.matcher(expression).find()) {
			//递归分析
			return analysis(expression, pattern, relation);
		}
		
		return expression;
	}
}
